package ru.xpparty.scanner;

import org.apache.commons.cli.*;
import ru.xpparty.scanner.model.ScanRequest;

/**
 * Implementation for parsing command line arguments
 * into the POJO(plain old java object)
 * 
 * @author xp.party
 *
 */
public class ArgumentBuilderImpl implements ArgumentsBuilder {
    private static final String DASH = "-";
	private static final int SECOND_PORT = 1;
	private static final int FIRST_PORT = 0;
	private static final String PORT_ARG = "p";
    private static final String HOST_ARG = "h";
    private static final String DEFAULT = "default";

    private Parser parser;
    private Options options;


    /**
	 * Performs parsing of command line arguments
	 * into the POJO(plain old java object)
	 * 
	 * @param args command line arguments
	 * @return parsed POJO
	 */
    @Override
    public ScanRequest build(String[] args) {
        parser = new PosixParser();
        options = createOptions();
        try {
            return tryParse(args);
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
    
    /**
     * Creates options for command line interface
     * 
     * @return options for command line interface
     */
    private Options createOptions() {
        Options options = new Options();
        options.addOption(PORT_ARG, true, "ports");
        options.addOption(HOST_ARG, true, "hosts");
        return options;
    }

    /**
	 * Tries to perform parsing of command line arguments
	 * into the POJO(plain old java object)
	 * 
	 * @param args command line arguments
	 * @return parsed POJO
	 * @throws ParseException if wrong command line format
	 */
    private ScanRequest tryParse(String[] args) throws ParseException {    	
        CommandLine line = parser.parse(options, args);
        String ports = line.getOptionValue(PORT_ARG, DEFAULT);
        String host = line.getOptionValue(HOST_ARG, DEFAULT);

        PortRange range = buildPortRange(ports);

        return new ScanRequest(host, range);
    }

    /**
     * Builds port range from ports command line arguments
     * 
     * @param ports command line arguments
     * @return builded port range from command line arguments
     */
	private PortRange buildPortRange(String ports) {		
        String[] splittedPorts = ports.split(DASH);
        if (isOnePort(splittedPorts)) {
            return new PortRange(firstPort(splittedPorts), firstPort(splittedPorts));
        } else if (isRangeOfPorts(splittedPorts)) {
            return new PortRange(firstPort(splittedPorts), secondPort(splittedPorts));
        }    
        throw new IllegalArgumentException();
	}
	
	/**
     * Returns true if one port presented
     * 
     * @param port
     * @return true if one port presented
     */
    private boolean isOnePort(String[] port) {
        return port.length == 1;
    }
    
    /**
     * Returns true if range of ports presented
     * 
     * @param ports array of string with splited ports
     * @return true if range of ports presented
     */
    private boolean isRangeOfPorts(String[] ports) {
        return ports.length == 2;
    }
    
	private int firstPort(String[] splittedPorts) {
		return Integer.parseInt(splittedPorts[FIRST_PORT]);
	}
	
	private int secondPort(String[] splittedPorts) {
		return Integer.parseInt(splittedPorts[SECOND_PORT]);
	}	  
    
    
}
